package nc.bs.gl.util;

import nc.bs.dao.BaseDAO;
import nc.bs.framework.common.NCLocator;
import nc.jdbc.framework.processor.MapListProcessor;
import nc.vo.pub.BusinessException;
import nc.vo.pub.lang.UFBoolean;
import nc.vo.pub.lang.UFDouble;
import nccloud.pubitf.gl.account.IAccountReportWebService;

import java.io.*;
import java.util.*;
import java.util.stream.Collectors;

public class RePortUtil {
    private BaseDAO baseDAO;
    /**
     * 获取所有辅助余额的PK
     * @param pks
     * @param fzxnName
     * @param pk_fzmx
     * @param nyear
     * @param nmonth
     * @return
     * @throws BusinessException
     */
    public static List<String> getAllPks(List<String> pks ,String fzxnName,String pk_fzmx, String nyear,String nmonth) throws BusinessException {
        ArrayList<String> lists = new ArrayList<>();
        String xmpk = String.join(",", pks.toArray(new String[pks.size()]));
//        String xmpk1 = StringUtils.join(pks.toArray(new String[pks.size()]), ",");
        Map<String, Object> xmMap = RePortUtil.buildFZMXMap(fzxnName, pk_fzmx, nyear, nmonth, xmpk);
//        Map<String, Object> res = new AssBalanceQueryBO().queryAssBalance(xmMap);
        IAccountReportWebService lookup = NCLocator.getInstance().lookup(IAccountReportWebService.class);
        Map<String, Object> res = lookup.queryAssBalance(xmMap);
        if(res != null && !res.isEmpty()){
            List<Map<String,Object>> data = (List<Map<String,Object>>)res.get("data");
            if (data != null && !data.isEmpty()) {
                List<Map<String,Object>> pagedata = (List<Map<String,Object>>)data.get(0).get("pagedata");
                if (pagedata != null && !pagedata.isEmpty()) {
                    for (Map<String, Object> mdata : pagedata) {
                        if(mdata != null  && !mdata.isEmpty()){
                            Object pk_checkvalue1 = mdata.get("pk_checkvalue1");
                            if (pk_checkvalue1 != null && !"".equals(pk_checkvalue1)) {
                                if (!lists.contains(pk_checkvalue1)) {
                                    lists.add(pk_checkvalue1.toString());
                                }
                            }
                        }
                    }
                }
            }
        }
        return lists;
    }

    /**
     * 辅助明细账数据处理
     * @param res       辅助明细账查询接过集合
     * @param nYear     年度
     * @param pk_year   年度PK
     * @param nMonth     月份
     * @param pk_month   月份Pk
     * @return 1:年度,2月份,3档案PK,4档案编码,5档案名称,6本月期初余额,7本月借方累计,8本月贷方累计,
     *  9本月合计期末余额,10本年累计期初余额,11本年借方累计,12本年贷方累计,13本年累计期末余额
     * @throws BusinessException
     */
    public static Object[] FXMXHandlerResult(Map<String, Object> res,String nYear, String pk_year,
                                               String nMonth, String pk_month) throws  BusinessException{
        if(res == null || res.isEmpty())return null;
        List<HashMap<String,Object>> pagedatas = (ArrayList<HashMap<String,Object>>)res.get("data");
        if(pagedatas == null || pagedatas.isEmpty()) return null;
        String pk = "";
        String code = "";
        String name = "";
        Object fx = "";
        Object[] resdata = new Object[15];
        UFDouble qcye = new UFDouble(0);
        UFDouble bqjf = new UFDouble(0);
        UFDouble bqdf = new UFDouble(0);
        UFDouble dflj = new UFDouble(0);
        UFDouble jflj = new UFDouble(0);
        UFDouble qmye = new UFDouble(0);
        List<HashMap<String,Object>> datas = (ArrayList<HashMap<String,Object>>)pagedatas.get(0).get("pagedata");
        if(datas == null || datas.isEmpty()) return null;
        for (HashMap<String, Object> data : datas) {
//            本年累计期初余额	本年累计余额-本年贷方累+本年借方累计
//            本月期末余额	本月合计余额-本月借方方累计+本月贷方方累计
            if (!"期初".equals(data.get("mark")) && !"本月合计".equals(data.get("mark"))
                    && !"本年累计".equals(data.get("mark")) && "".equals(code)) {
                pk = data.get("pk_checkvalue1").toString();
                code = data.get("checkvaluecode1").toString();
                int index = data.get("showname1").toString().lastIndexOf("/") +1;
                name = data.get("showname1").toString().substring(index);
//                name = data.get("showname1").toString();
            } else if ("总计".equals(data.get("mark"))) {
                qcye = "".equals(data.get("initlocamount"))  ? qcye : new UFDouble(data.get("initlocamount").toString());
                bqjf = "".equals(data.get("debitlocamount"))  ? bqjf : new UFDouble(data.get("debitlocamount").toString());
                bqdf = "".equals(data.get("creditlocamount"))  ? bqdf : new UFDouble(data.get("creditlocamount").toString());
                jflj = "".equals(data.get("debitaccumlocamount"))  ? jflj : new UFDouble(data.get("debitaccumlocamount").toString());
                dflj = "".equals(data.get("creditaccumamount"))  ? dflj : new UFDouble(data.get("creditaccumamount").toString());
                qmye = "".equals(data.get("endamount"))  ? qmye : new UFDouble(data.get("endamount").toString());
                fx = data.get("endorients");

            }
        }
        resdata[0]  = nYear;
        resdata[1]  = pk_year;
        resdata[2]  = nMonth;
        resdata[3]  = pk_month;
        resdata[4]  = pk;
        resdata[5]  = code;
        resdata[6]  = name;
        resdata[7]  = qcye;
        resdata[8]  = bqjf;
        resdata[9]  = bqdf;
        resdata[10] = jflj;
        resdata[11] = dflj;
        resdata[12] = qmye;
        resdata[13] = fx;
        resdata[14] = "0001A210000000000JB9";
        return resdata;

    }


    /**
     * 构建辅助余额查询条件
     * @param fzxmName   辅助明细核酸类型名称
     * @param pk_fzmx    辅助明细核酸类型PK
     * @param nyear      年度
     * @param nmonth     月份
     * @param pk_xm      辅助核酸查询项目PK
     * @return
     * @throws BusinessException
     */
    public static Map<String, Object> buildFZMXMap(String fzxmName , String pk_fzmx,String nyear, String nmonth, String pk_xm) throws BusinessException {
        Map<String, Object> param = new HashMap<String, Object>();
        List<Object> pk_glorgbooks = new ArrayList<>();
        pk_glorgbooks.add("1001A210000000000R84");
        param.put("pk_glorgbooks", pk_glorgbooks);
        param.put("pk_orgs", new  ArrayList<>());
        param.put("multiBusi", new UFBoolean(false));
        param.put("multliabcenter", new UFBoolean(false));
        param.put("pk_liabilitycenter", new ArrayList<>());
        param.put("useSubjVersion", new UFBoolean(false));
        param.put("subjVersion", "");
        param.put("subjVersionShow", "");
        ArrayList<Object> qryObjs = new ArrayList<>();
        Map<String, String> kjkmmap = new HashMap<>();
        kjkmmap.put("name","会计科目");
        kjkmmap.put("pk_checktype","会计科目");
        kjkmmap.put("pk_checkvalue","");
        kjkmmap.put("headEle","N");
        kjkmmap.put("accEle","N");
        kjkmmap.put("includeSub","N");
        Map<String, String> xmmap = new HashMap<>();
        xmmap.put("name",fzxmName);
        xmmap.put("pk_checktype",pk_fzmx);
        xmmap.put("headEle","N");
        xmmap.put("accEle","N");
        xmmap.put("includeSub","N");
        String pk_checkvalue = "";
        if(!"".equals(pk_xm)){
            pk_checkvalue = pk_xm;
        }
        xmmap.put("pk_checkvalue",pk_checkvalue);
        qryObjs.add(kjkmmap);
        qryObjs.add(xmmap);
        param.put("qryObjs", qryObjs);
        param.put("selectionState", "true");
        param.put("beginyear", nyear);
        param.put("beginperiod", nmonth);
        param.put("begindate", nyear+"-"+nmonth+"-01");
        param.put("endyear", nyear);
        param.put("endperiod", nmonth);
        param.put("enddate", nyear+"-"+nmonth+"-31");
        param.put("includeUnTallyed", "Y");
        param.put("includeError", "Y");
        param.put("includeTransfer", "N");
        param.put("includeReClassify", "N");
        param.put("pk_currtype", "本币");
        param.put("currTypeName", "本币");
        param.put("return_currtype", "1");
        param.put("balanceDirection", "-1");
        param.put("balanceRangeFrom","");
        param.put("balanceRangeTo","");
        param.put("ckShowZeroAmount", new UFBoolean(false));
        param.put("ckNotShowZeroOccurZeroBalance",new UFBoolean(false));
        param.put("ckShowZeroBalance",new UFBoolean(false));
        param.put("showzerooccurEdit",new UFBoolean(false));
        param.put("showzerobalanceEdit",new UFBoolean(false));
        param.put("ckNotShowZeroOccurZeroBalanceEdit",new UFBoolean(false));
        param.put("rbCorpJun","N");
        param.put("qryObjPlusCorp",false);
        param.put("cbCorpSubjDspBase","");
        param.put("qryObjPlusCorp",new UFBoolean(false));
        param.put("cbQryByCorpAss",new UFBoolean(false));
        param.put("mutibook", "N");
        param.put("showzerobalanceoccur", "Y");
        param.put("currplusacc", "Y");
        param.put("sumbysubjtype", "N");
        param.put("twowaybalance", "N");
        param.put("istree", "Y");
        param.put("appcode", "20023055");
        param.put("index", "");
        param.put("pk_fccurrtype", "");
        param.put("fcrate", "");
        param.put("subjectType", "0");
        param.put("returnSubjectType", "1");
        return param;
    }

    /**
     * 处理父级项目
     * @param datas
     * @return
     * @throws BusinessException
     */
    public static Collection<Object[]> handParentProject(Collection<Object[]> datas) throws BusinessException{
        RePortUtil util = new RePortUtil();
        Map<String, Object[]> dmap = new HashMap<>();
        for (Object[] data : datas) {
            Object xmcode = data[5];
            String key = String.valueOf(data[4]); // 项目pk
            UFDouble qcye = "贷".equals(data[13]) ? new UFDouble(-1).multiply((UFDouble)data[7]) : (UFDouble)data[7] ;
//            UFDouble bqjf = "贷".equals(data[13]) ? new UFDouble(-1).multiply((UFDouble)data[8]) : (UFDouble)data[8] ;
//            UFDouble bqdf = "贷".equals(data[13]) ? new UFDouble(-1).multiply((UFDouble)data[9]) : (UFDouble)data[9] ;
//            UFDouble jflj = "贷".equals(data[13]) ? new UFDouble(-1).multiply((UFDouble)data[10]) : (UFDouble)data[10] ;
//            UFDouble dflj = "贷".equals(data[13]) ? new UFDouble(-1).multiply((UFDouble)data[11]) : (UFDouble)data[11] ;
            UFDouble qmye = "贷".equals(data[13]) ? new UFDouble(-1).multiply((UFDouble)data[12]) : (UFDouble)data[12] ;
            UFDouble bqjf = (UFDouble)data[8] ;
            UFDouble bqdf = (UFDouble)data[9] ;
            UFDouble jflj = (UFDouble)data[10] ;
            UFDouble dflj = (UFDouble)data[11] ;
            dmap.put(key,data);
            List<Map<String, Object>> flists = util.getParenProject(xmcode);
            if (flists == null || flists.isEmpty()) {
                continue;
            }
            for (Map<String, Object> flist : flists) {
                String id = flist.get("id").toString();
                String defCode = flist.get("code").toString();
                String defName = flist.get("name").toString();
                if (key.equals(id)) continue;
                if (dmap.containsKey(id)) { // 说明上级已存在
                    Object[] obj = dmap.get(id);
                    obj[7] = ((UFDouble)obj[7]).add(qcye);
                    obj[8] = ((UFDouble)obj[8]).add(bqjf);
                    obj[9] = ((UFDouble)obj[9]).add(bqdf);
                    obj[10] = ((UFDouble)obj[10]).add(jflj);
                    obj[11] = ((UFDouble)obj[11]).add(dflj);
                    obj[12] = ((UFDouble)obj[12]).add(qmye);
                    obj[13] = "";
                    dmap.put(id, obj);
                }else{ // 说明上级不存在
                    Object[] cpData = util.deepCopy(data);
                    cpData[4] = id; // key
                    cpData[5] = defCode; // code
                    cpData[6] = defName; // name
                    cpData[7] = qcye;
                    cpData[8] = bqjf;
                    cpData[9] = bqdf;
                    cpData[10] = jflj;
                    cpData[11] = dflj;
                    cpData[12] = qmye;
                    cpData[13] = "";
                    dmap.put(id,cpData);
                }
            }

        }
        if (!dmap.isEmpty()) {
            List<Object[]> objs = new ArrayList<>();
            for (String s : dmap.keySet()) {
                objs.add(dmap.get(s));
            }
            datas = objs.stream().collect(Collectors.toCollection(ArrayList::new));
            for (Object[] data : datas) {
                Object fx = data[13];
                if ("".equals(fx)) { // 说明是上级进行处理借贷方向
                    UFDouble qcye = (UFDouble)data[7];
                    UFDouble bqjf = (UFDouble)data[8];
                    UFDouble jflj = (UFDouble)data[10];
                    if (qcye.getDouble() < 0 || bqjf.getDouble() < 0 || jflj.getDouble() < 0 ){ // 说明是贷方所有金额取反
                        data[7] = new UFDouble(-1).multiply((UFDouble)data[7]);
                        data[8] = new UFDouble(1).multiply((UFDouble)data[8]);
                        data[9] = new UFDouble(1).multiply((UFDouble)data[9]);
                        data[10] = new UFDouble(1).multiply((UFDouble)data[10]);
                        data[11] = new UFDouble(1).multiply((UFDouble)data[11]);
                        data[12] = new UFDouble(-1).multiply((UFDouble)data[12]);
                        data[13] = "贷";
                    }else if (qcye.getDouble() > 0 || bqjf.getDouble() > 0 || jflj.getDouble() > 0  ){
                        data[13] = "借";
                    }else{
                        data[13] = "平";
                    }
                }
            }
            sortCollectionByIndex4(datas);
        }
        return datas;
    }

    /**
     * 排序
     * @param datas
     */
    public static void sortCollectionByIndex4(Collection<Object[]> datas) {
        // 1. 将 Collection 转换为 List
        List<Object[]> dataList = new ArrayList<>(datas);

        // 2. 定义比较器：按 data[4] 升序排序
        Comparator<Object[]> comparator = (a, b) -> {
            // 获取索引4的值，处理 null 情况
            String strA = (a[4] != null) ? a[4].toString() : "";
            String strB = (b[4] != null) ? b[4].toString() : "";
            return strA.compareTo(strB); // 字符串自然序比较
        };

        // 3. 执行排序
        dataList.sort(comparator);
    }
    /**
     * 获取当前项目的父级项目
     * @param xmcode
     * @return
     * @throws BusinessException
     */
    private String buildParenProjectSQL(Object xmcode) throws BusinessException{
        StringBuilder sql = new StringBuilder();
        sql.append(" SELECT \n" );
        sql.append("   ht.pk_defdoc id, ht.code code, \n" );
        sql.append("   ht.name name, ht.pid \n" );
        sql.append(" FROM bd_defdoc  ht \n" );
        sql.append(" START WITH pk_defdoclist = '1001A210000000000RAX' and ht.code = '"+xmcode+"'  \n" );
        sql.append(" CONNECT BY PRIOR ht.pid = ht.pk_defdoc  ");
        return sql.toString();
    }

    /**
     * 获取父级项目
     * @param xmcode
     * @return
     * @throws BusinessException
     */
    private List<Map<String,Object>> getParenProject(Object xmcode) throws BusinessException{
        List<Map<String, Object>> lists = new ArrayList<>();
        lists = (List<Map<String, Object>> )this.getBaseDAO().executeQuery(this.buildParenProjectSQL(xmcode), new MapListProcessor());
        return lists;
    }

    /**
     * 深拷贝Object[]数组
     * @param original 原始数组
     * @return 深拷贝后的数组
     * @throws BusinessException 类找不到异常
     */
    public Object[] deepCopy(Object[] original) throws BusinessException {
        if (original == null) {
            return null;
        }
        ByteArrayOutputStream bos = null;
        ObjectOutputStream oos = null;
        ByteArrayInputStream bis = null;
        ObjectInputStream ois = null;
        try{
            // 使用序列化方式实现深拷贝
            bos = new ByteArrayOutputStream();
            oos = new ObjectOutputStream(bos);
            oos.writeObject(original);
            bis = new ByteArrayInputStream(bos.toByteArray());
            ois = new ObjectInputStream(bis);
            return  (Object[]) ois.readObject();
        }catch(Exception e){
            throw new BusinessException(e.getMessage());
        }finally {
            try {
                if (bos != null )  bos.close();
                if (oos != null )  oos.close();
                if (bis != null )  bis.close();
                if (ois != null )  ois.close();
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        }
    }

    public BaseDAO getBaseDAO() {
        return this.baseDAO == null ? new BaseDAO() : this.baseDAO;
    }
}
